package com.millstein.tsinglog.annotationHandler;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.millstein.tsinglog.annotation.ShiroAccessLog;
import com.millstein.tsinglog.commons.constant.SystemConstant;
import com.millstein.tsinglog.utils.AspectUtils;
import com.millstein.tsinglog.utils.IpUtils;
import com.millstein.tsinglog.utils.RequestUtils;
import com.millstein.tsinglog.model.pojo.Log;
import com.millstein.tsinglog.result.ProfileResult;
import com.millstein.tsinglog.service.LogService;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * AOP切面记录日志
 */
@Slf4j
@Aspect
@Component
public class ShiroAccessLogHandler {

    @Autowired
    private LogService logService;

    @Pointcut(value = "@annotation(com.millstein.tsinglog.annotation.ShiroAccessLog)")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object writeLog(ProceedingJoinPoint point) throws Throwable {

        //先执行业务
        Object result = point.proceed();

        try {
            handle(point);
        } catch (Exception e) {
            log.error("日志记录出错!", e);
        }

        return result;
    }

    private void handle(ProceedingJoinPoint point) throws Exception {

        ObjectMapper mapper = new ObjectMapper();

        // 获取当前操作的方法
        Method currentMethod = AspectUtils.INSTANCE.getMethod(point);

        // 获取操作名称
        ShiroAccessLog annotation = currentMethod.getAnnotation(ShiroAccessLog.class);

        boolean save = annotation.save();
        String bizName = AspectUtils.INSTANCE.parseParams(point.getArgs(), annotation.value());
        String ua = RequestUtils.getUa();

        Subject subject = SecurityUtils.getSubject();
        ProfileResult profile = (ProfileResult) subject.getPrincipals().getPrimaryPrincipal();

        Log sysLog = new Log();

        sysLog.setUserId(profile.getId());
        sysLog.setContent(String.format("用户: [%s] | 操作: %s", profile.getUsername(), bizName));
        sysLog.setType(SystemConstant.TYPE_MANAGER);

        log.info("用户[{} | {}] {} - {} {}", profile.getUsername(), IpUtils.getRealIp(RequestUtils.getRequest()), bizName,
                RequestUtils.getMethod(), RequestUtils.getRequestUrl());

        if (!save) {
            return;
        }

        sysLog.setLogLevel(SystemConstant.LEVEL_INFO);
        sysLog.setIp(RequestUtils.getIp());
        sysLog.setReferer(RequestUtils.getReferer());
        sysLog.setRequestUrl(RequestUtils.getRequestUrl());
        sysLog.setUa(ua);
        sysLog.setParams(mapper.writeValueAsString(RequestUtils.getParametersMap()));

        try {
            UserAgent agent = UserAgent.parseUserAgentString(ua);
            sysLog.setBrowser(agent.getBrowser().getName());
            sysLog.setOs(agent.getOperatingSystem().getName());
            logService.insertLog(sysLog);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}
